package com.github.m6d21.sso.business.controller.test;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.github.m6d21.sso.business.controller.test.model.Brand;
import com.github.m6d21.sso.business.controller.test.model.Car;
import com.github.m6d21.sso.business.controller.test.model.ExcelCarInfo;
import com.github.m6d21.sso.business.controller.test.model.Model;
import com.github.m6d21.sso.business.controller.test.model.Series;
import com.github.m6d21.sso.common.util.excel.ExcelHelper;
import com.github.m6d21.sso.support.enums.StatusCode;
import com.github.m6d21.sso.support.model.Response;
import com.github.m6d21.sso.support.util.ResponseUtil;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 *<p>
 *
 *</p>
 *
 * @author liuyang
 * @date 2018-12-07 Fri 13:27:18
 * @since 1.0.0
 */
@Api(value = "test-common", description = "通用测试")
@Validated
@Slf4j
@RestController
@RequestMapping("/test/common")
public class CommonController {


    private RestTemplate restTemplate;

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        this.rebuildRestTemplate(restTemplate);
    }

    @ApiOperation(value = "获取网络文件", httpMethod = "GET")
    @GetMapping("/test/enum")
    @ResponseBody
    public Response<Object> getEnums() {

        return ResponseUtil.success(StatusCode.SERVER_ERROR);
    }

    @ApiOperation(value = "获取网络文件", httpMethod = "GET")
    @GetMapping("/get/network/file")
    @ResponseBody
    public Response<List<ExcelCarInfo>> getNetworkFile
        (@NotNull(message = "URL不能为空") @RequestParam("url") String urlStr) {
        List<ExcelCarInfo> data = null;
        try {
            URL url = new URL(urlStr);
            ExcelHelper helper = ExcelHelper.newInstance(ExcelCarInfo.class);
            data = helper.parseExcel(url.openConnection().getInputStream());
            processData(data);
        } catch (Exception e) {
            ResponseUtil.fail(StatusCode.FAIL.getCode(), e.getMessage());
        }
        return ResponseUtil.success(data);
    }

    @ApiOperation(value = "测试下载文件", httpMethod = "GET", produces = "application/octet-stream")
    @GetMapping(value = "/download/car/excel")
    public void downloadCarExcel
        (@NotNull(message = "fileName不能为空") @RequestParam("fileName") String fileName,
            HttpServletResponse response) {
        List<ExcelCarInfo> data = null;

        InputStream isp = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        OutputStream osp = null;
        ByteArrayOutputStream outputStream = null;
        try {
            ExcelCarInfo carInfo = new ExcelCarInfo();
            carInfo.setVinNumber("");
            carInfo.setBrand("brand-859");
            carInfo.setBrandName("AC Schnitzer");
            carInfo.setSeries("series-50633");
            carInfo.setSeriesName("AC M3");
            carInfo.setModel("209725");
            carInfo.setModelName("2015款 AC M3 ACS3 sport");
//            carInfo.setMileage(71000L);
            carInfo.setFirstLicensePlateDate(new Date(new java.util.Date().getTime()));
            carInfo.setIsNewCar(0);
            carInfo.setColor("白色");

            response.reset();
            response.setCharacterEncoding("utf8");
            response.setContentType("application/octet-stream");
            response.setHeader("Content-disposition", "attachment; filename="
                + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));

            List<ExcelCarInfo> carInfoList = new ArrayList<>();
            carInfoList.add(carInfo);
            osp = response.getOutputStream();
            ExcelHelper helper = ExcelHelper.newInstance(ExcelCarInfo.class);
            isp = helper.exportExcel(carInfoList);
            //构造读取流
            bis = new BufferedInputStream(isp);
            //构造输出流
            bos = new BufferedOutputStream(osp);
            IOUtils.copy(bis, osp);
            bos.flush();
        } catch (Exception e) {
            log.error("下载Excel失败, error:{}", e);
        } finally {
            close(bis);
            close(bos);
            close(isp);
            close(osp);
        }
    }

    @SuppressWarnings("all")
    private void processData(List<ExcelCarInfo> excelCarInfoList) {
        if (CollectionUtils.isEmpty(excelCarInfoList)) {
            return;
        }

        int successCounter = 0;
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        excelCarInfoList.forEach(excelCarInfo -> executorService.submit(new Runnable() {
            @Override
            public void run() {
                Boolean success = saveData(excelCarInfo);
                if (!success) {
                    log.error("保存失败{}", excelCarInfo);
                }
            }
        }));

    }

    private Boolean saveData(ExcelCarInfo excelCarInfo) {
        if (excelCarInfo == null) {
            return false;
        }

        if ("黑色".equals(excelCarInfo.getColor())) {
            return true;
        }
        return false;
    }

    private void close(Closeable x) {
        if (x != null) {
            try {
                x.close();
            } catch (IOException e) {
                log.error("关闭流或文件失败, error{}", e);
            }
        }
    }

    @ApiOperation(value = "爬取车辆品牌信息", httpMethod = "GET")
    @GetMapping("/get/brand/info")
    @ResponseBody
    public Response<Object> getBrandInfo() {
        List<Brand> brandList = this.fetchBrandList();
        int count = 5;
        for (Brand brand : brandList) {
            if (StringUtils.isEmpty(Optional.ofNullable(brand).map(Brand::getCode).orElse(null))) {
                continue;
            }
            List<Series> seriesList = fetchSeriesList(brand.getCode());
            if (CollectionUtils.isEmpty(seriesList)) {
                continue;
            }
            for (Series series : seriesList) {
                if (StringUtils.isEmpty(Optional.ofNullable(series).map(Series::getCode).orElse(null))) {
                    continue;
                }
                series.setModelList(fetchModelList(series.getCode()));
            }
            brand.setSeriesList(seriesList);
        }

        List<Car> carList = new ArrayList<>(40960);
        for (Brand brand : brandList) {
            if (brand == null || brand.getSeriesList() == null || brand.getSeriesList().size() == 0) {
                continue;
            }
            for (Series series : brand.getSeriesList()) {
                if (series == null || series.getModelList() == null || series.getModelList().size() == 0) {
                    continue;
                }
                for (Model model : series.getModelList()) {
                    if (model == null) {
                        continue;
                    }
                    Car car = new Car();
                    car.setBrandCode(brand.getCode());
                    car.setBrandName(brand.getName());
                    car.setSeriesCode(series.getCode());
                    car.setSeriesName(series.getName());
                    car.setModelCode(model.getModelCode());
                    car.setModelName(model.getModelName());
                    carList.add(car);
                }
            }
        }
        try {
            File file = new File("car-brand-series-model.xlsx");
            if (!file.exists()) {
                boolean s = file.createNewFile();
                if (!s) {
                    throw new RuntimeException("无法创建文件");
                }
            }
            OutputStream outputStream = new FileOutputStream(file);

            ExcelHelper helper = ExcelHelper.<Car>newInstance(Car.class);
            helper.exportExcel(carList, outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private List<Brand> fetchBrandList() {
        String brandUrl = "http://webc.souche.com/car-model/brand/brands.jsonp?callback={callback}&sites={sites}";
        Map<String, Object> param = new HashMap<>(4);
        param.put("callback", "__jp0");
        param.put("sites", "SOUCHE,CH168");
        ResponseEntity<JSONPObject> responseEntity = null;
        try {
            responseEntity = restTemplate.getForEntity(brandUrl, JSONPObject.class, param);
        } catch (RestClientException e) {
            e.printStackTrace();
            return new ArrayList<>(0);
        }
        List<Object> list = Optional.ofNullable(responseEntity.getBody()).map(JSONPObject::getParameters)
            .orElse(new ArrayList<>(0));
        JSONObject jsonObject = (JSONObject) list.get(0);
        JSONArray jsonArray = jsonObject.getJSONArray("data");
        return jsonArray.toJavaList(Brand.class);
    }

    private List<Series> fetchSeriesList(String brandCode) {
        String brandUrl = "http://webc.souche.com/car-model/series/getSeriesByBrand.jsonp?callback={callback}&sites={sites}&brand_code={brand_code}";
        Map<String, Object> param = new HashMap<>(4);
        param.put("callback", "__jp1");
        param.put("sites", "SOUCHE,CH168");
        param.put("brand_code", brandCode);
        ResponseEntity<JSONPObject> responseEntity = null;
        try {
            responseEntity = restTemplate.getForEntity(brandUrl, JSONPObject.class, param);
        } catch (RestClientException e) {
            e.printStackTrace();
            return new ArrayList<>(0);
        }
        List<Object> list = Optional.ofNullable(responseEntity.getBody()).map(JSONPObject::getParameters)
            .orElse(new ArrayList<>(0));
        JSONObject jsonObject = (JSONObject) list.get(0);
        JSONArray jsonArray = jsonObject.getJSONArray("data");
        return jsonArray.toJavaList(Series.class);
    }

    private List<Model> fetchModelList(String seriesCode) {
        String brandUrl = "http://webc.souche.com/car-model/api/model/get.jsonp?callback={callback}&sites={sites}&series_code={series_code}";
        Map<String, Object> param = new HashMap<>(4);
        param.put("callback", "__jp2");
        param.put("sites", "SOUCHE,CH168");
        param.put("series_code", seriesCode);
        ResponseEntity<JSONPObject> responseEntity = null;
        try {
            responseEntity = restTemplate.getForEntity(brandUrl, JSONPObject.class, param);
        } catch (RestClientException e) {
            e.printStackTrace();
            return new ArrayList<>(0);
        }
        List<Object> list = Optional.ofNullable(responseEntity.getBody()).map(JSONPObject::getParameters)
            .orElse(new ArrayList<>(0));
        JSONObject jsonObject = (JSONObject) list.get(0);
        JSONArray jsonArray = jsonObject.getJSONArray("data");
        return jsonArray.toJavaList(Model.class);
    }

    private void rebuildRestTemplate(RestTemplate restTemplate) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);

        restTemplate.setMessageConverters(Lists.newArrayList(fastJsonHttpMessageConverter));
    }

}
